//===================================================================================
// Microsoft patterns & practices
// Composite Application Guidance for Windows Presentation Foundation and Silverlight
//===================================================================================
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===================================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===================================================================================
using System;
using System.Windows.Input;

    /// <summary>
    /// An <see cref="ICommand"/> whose delegates can be attached for <see cref="Execute"/> and <see cref="CanExecute"/>.
    /// It also implements the <see cref="IActiveAware"/> interface, which is
    /// useful when registering this command in a <see cref="CompositeCommand"/>
    /// that monitors command's activity.
    /// </summary>
public abstract class DelegateCommandBase : ICommand
{
	private readonly Action<object> executeMethod;
	private readonly Func<object, bool> canExecuteMethod;
	private bool _isActive;

#if !SILVERLIGHT
        private List<WeakReference> _canExecuteChangedHandlers;
#endif

	/// <summary>
	/// Createse a new instance of a <see cref="DelegateCommandBase"/>, specifying both the execute action and the can execute function.
	/// </summary>
	/// <param name="executeMethod">The <see cref="Action"/> to execute when <see cref="ICommand.Execute"/> is invoked.</param>
	/// <param name="canExecuteMethod">The <see cref="Func{Object,Bool}"/> to invoked when <see cref="ICommand.CanExecute"/> is invoked.</param>
	protected DelegateCommandBase(Action<object> executeMethod, Func<object, bool> canExecuteMethod)
	{
		if (executeMethod == null || canExecuteMethod == null)
			throw new ArgumentNullException("executeMethod", "DelegateCommandDelegatesCannotBeNull");

		this.executeMethod = executeMethod;
		this.canExecuteMethod = canExecuteMethod;
	}

	/// <summary>
	/// Gets or sets a value indicating whether the object is active.
	/// </summary>
	/// <value><see langword="true" /> if the object is active; otherwise <see langword="false" />.</value>
	public bool IsActive
	{
		get { return _isActive; }
		set
		{
			if (_isActive != value)
			{
				_isActive = value;
				OnIsActiveChanged();
			}
		}
	}

#if SILVERLIGHT
	/// <summary>
	/// Raises <see cref="ICommand.CanExecuteChanged"/> on the UI thread so every 
	/// command invoker can requery <see cref="ICommand.CanExecute"/> to check if the
	/// <see cref="CompositeCommand"/> can execute.
	/// </summary>
	protected virtual void OnCanExecuteChanged()
	{
		var handlers = CanExecuteChanged;
		if (handlers != null)
		{
			handlers(this, EventArgs.Empty);
		}
	}
#else

        /// <summary>
        /// Raises <see cref="ICommand.CanExecuteChanged"/> on the UI thread so every 
        /// command invoker can requery <see cref="ICommand.CanExecute"/> to check if the
        /// <see cref="CompositeCommand"/> can execute.
        /// </summary>
        protected virtual void OnCanExecuteChanged()
        {
            WeakEventHandlerManager.CallWeakReferenceHandlers(this, _canExecuteChangedHandlers);
        }
#endif

	/// <summary>
	/// Raises <see cref="DelegateCommandBase.CanExecuteChanged"/> on the UI thread so every command invoker
	/// can requery to check if the command can execute.
	/// <remarks>Note that this will trigger the execution of <see cref="DelegateCommandBase.CanExecute"/> once for each invoker.</remarks>
	/// </summary>
	[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate")]
	public void RaiseCanExecuteChanged()
	{
		OnCanExecuteChanged();
	}

	/// <summary>
	/// Fired if the <see cref="IsActive"/> property changes.
	/// </summary>
	public virtual event EventHandler IsActiveChanged;

	/// <summary>
	/// This raises the <see cref="DelegateCommandBase.IsActiveChanged"/> event.
	/// </summary>
	protected virtual void OnIsActiveChanged()
	{
		EventHandler isActiveChangedHandler = IsActiveChanged;
		if (isActiveChangedHandler != null) isActiveChangedHandler(this, EventArgs.Empty);
	}

	void ICommand.Execute(object parameter)
	{
		Execute(parameter);
	}

	bool ICommand.CanExecute(object parameter)
	{
		bool result = CanExecute(parameter);
		return result;
	}

	/// <summary>
	/// Executes the command with the provided parameter by invoking the <see cref="Action{Object}"/> supplied during construction.
	/// </summary>
	/// <param name="parameter"></param>
	protected void Execute(object parameter)
	{
		executeMethod(parameter);
	}

	/// <summary>
	/// Determines if the command can execute with the provided parameter by invoing the <see cref="Func{Object,Bool}"/> supplied during construction.
	/// </summary>
	/// <param name="parameter">The parameter to use when determining if this command can execute.</param>
	/// <returns>Returns <see langword="true"/> if the command can execute.  <see langword="False"/> otherwise.</returns>
	protected bool CanExecute(object parameter)
	{
		return canExecuteMethod == null || canExecuteMethod(parameter);
	}

#if SILVERLIGHT
	/// <summary>
	/// Occurs when changes occur that affect whether or not the command should execute. 
	/// </summary>
	public event EventHandler CanExecuteChanged;
#else
        /// <summary>
        /// Occurs when changes occur that affect whether or not the command should execute. You must keep a hard
        /// reference to the handler to avoid garbage collection and unexpected results. See remarks for more information.
        /// </summary>
        /// <remarks>
        /// When subscribing to the <see cref="ICommand.CanExecuteChanged"/> event using 
        /// code (not when binding using XAML) will need to keep a hard reference to the event handler. This is to prevent 
        /// garbage collection of the event handler because the command implements the Weak Event pattern so it does not have
        /// a hard reference to this handler. An example implementation can be seen in the CompositeCommand and CommandBehaviorBase
        /// classes. In most scenarios, there is no reason to sign up to the CanExecuteChanged event directly, but if you do, you
        /// are responsible for maintaining the reference.
        /// </remarks>
        /// <example>
        /// The following code holds a reference to the event handler. The myEventHandlerReference value should be stored
        /// in an instance member to avoid it from being garbage collected.
        /// <code>
        /// EventHandler myEventHandlerReference = new EventHandler(this.OnCanExecuteChanged);
        /// command.CanExecuteChanged += myEventHandlerReference;
        /// </code>
        /// </example>
        public event EventHandler CanExecuteChanged
        {
            add
            {
                WeakEventHandlerManager.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2);
            }
            remove
            {
                WeakEventHandlerManager.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value);
            }
        }
#endif
}
